package com.jungle.base.utils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

public class ReflectUtil {

    private ReflectUtil() {
    }

    /**
     * 获取类中所有字段，包括父类的字段
     *
     * @param clazz    指定的类
     * @param fieldMap 字段存放 Map
     */
    public static Map<String, Field> findAllField(Class<?> clazz, final Map<String, Field> fieldMap) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            fieldMap.putIfAbsent(field.getName(), field);
        }
        Class<?> superClass = clazz.getSuperclass();

        return superClass == Object.class ? fieldMap : findAllField(superClass, fieldMap);
    }


    /**
     * 获取类中所有字段，包括父类的字段
     *
     * @param clazz     指定的类
     * @param fieldList 字段存放 List
     */
    public static List<Field> findAllField(Class<?> clazz, final List<Field> fieldList) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (count(fieldList, field) == 0) {
                // 名称相同的，保留子类的属性
                fieldList.add(field);
            }
        }
        Class<?> superClass = clazz.getSuperclass();

        return superClass == Object.class ? fieldList : findAllField(superClass, fieldList);
    }

    private static long count(List<Field> fieldList, Field field) {
        String fieldName = field.getName();
        return fieldList.stream().filter(f -> f.getName().equals(fieldName)).count();
    }

    /**
     * Retrieves the value of a specified field from an object.
     * This method attempts to access the specified field of the given object and returns its value.
     * If the field is not accessible, it temporarily modifies the accessibility of the field to retrieve the value.
     *
     * @param object the object from which to retrieve the field value
     * @param field  the field whose value is to be retrieved
     * @return the value of the specified field, or null if an IllegalAccessException occurs
     */
    public static Object getFieldValue(Object object, Field field) {
        try {
            // Check if the field can be accessed directly
            if (field.canAccess(object)) {
                return field.get(object);
            } else {
                // Temporarily set the field as accessible
                field.setAccessible(true);
                Object value = field.get(object);
                field.setAccessible(false);
                return value;
            }
        } catch (IllegalAccessException e) {
            // Return null if an IllegalAccessException occurs
            return null;
        }
    }
}
